package person.bangbang.im.Androidgin.UI;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import person.bangbang.im.Androidgin.Androidgin;
import person.bangbang.im.Androidgin.R;
import person.bangbang.im.Androidgin.Util.Log;
import person.bangbang.im.Androidgin.Util.Log.OnLogEvent;
import android.app.ListActivity;
import android.os.Bundle;
import android.os.Environment;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.Toast;
import android.widget.ToggleButton;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.CompoundButton.OnCheckedChangeListener;
/**
 * a dynamic debug tools.
 * 
 * NOTE currently fire this by press key D twice quickly (ContactList.THRESHOLD)
 * in ContactList.
 * 
 * BUG android:transcriptMode can not work. why?
 */
public class Debuger extends ListActivity implements OnLogEvent {
	private static final String TAG = "Debuger";
	private static final Boolean LOCAL_LOG = true;
	
	private static final String LOG_DIR = Androidgin.APP_DIR + "/log";
	
	private static final String V = Log.V;
	private static final String E = Log.E;
	private static final String D = Log.D;
	private static final String W = Log.W;
	private static final String I = Log.I;
	
	private EditText mFilterText;
	private Spinner mFilterLevel;
	private ListView mListView;
	
	
	private List<LogMessage> mList = new ArrayList<LogMessage>();
	/* log is needed? */
	private boolean mLogging = true;
	/* current log level */
	private int mLevel = Log.LEVEL_V;
	/* filter constraint. default to "", which will show ALL */
	private String mReg = "";
	
	private ArrayAdapter<String> mAdapter;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.debuger);
		
		
		mFilterText = ((EditText)findViewById(R.id.debug_filter_text));
		mFilterText.setOnKeyListener(new OnKeyListener() {
			public boolean onKey(View v, int keyCode, KeyEvent event) {
				switch (keyCode) {
				case KeyEvent.KEYCODE_ENTER:
				case KeyEvent.KEYCODE_DPAD_CENTER:
					mReg = ((EditText)v).getText().toString();
					if (LOCAL_LOG) Log.d(TAG, "filter constraint is: " + mReg);
					filter();
					
					return true;

				default:
					break;
				}
				return false;
			}
		});
		mFilterLevel = ((Spinner)findViewById(R.id.debug_filter_level));
//		ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(getApplicationContext(),
//                android.R.layout.simple_spinner_item,
//                new Integer[]{Log.LEVEL_E,
//                              Log.LEVEL_D,
//                              Log.LEVEL_W,
//                              Log.LEVEL_I,
//                              Log.LEVEL_V
//                          
//		});
		ArrayAdapter<String> adapter = new ArrayAdapter<String>(getApplicationContext(),
                android.R.layout.simple_spinner_item,
                new String[]{"Error",
                              "Debug",
                              "Warnning",
                              "Information",
                              "Verbose"
                          
		});
		mFilterLevel.setAdapter(adapter);
		mFilterLevel.setSelection(4); // Verbose default
		mFilterLevel.setOnItemSelectedListener(new OnItemSelectedListener() {
			public void onItemSelected(AdapterView<?> v, View parent,
					int position, long id) {
				mLevel = position;
				filter();
			}
		public void onNothingSelected(AdapterView<?> arg0) {}
		});
		//		((LinearLayout)findViewById(R.id.debug_controls)).setVisibility(View.GONE);
		((ToggleButton)findViewById(R.id.Toggle_filter)).setOnCheckedChangeListener(new OnCheckedChangeListener() {
			public void onCheckedChanged(CompoundButton buttonView,
					boolean isChecked) {
					if (isChecked) {
						mLogging = true;
						mFilterText.setEnabled(true);
						mFilterLevel.setEnabled(true);
						mLevel = mFilterLevel.getSelectedItemPosition();
						mReg = mFilterText.getText().toString();
						filter(); 
					} else {
						mLogging = false;
						mFilterText.setEnabled(false);
						mFilterLevel.setEnabled(false);
					}
			}
		});
		((ToggleButton)findViewById(R.id.Toggle_filter)).setVisibility(View.GONE);
	
		mAdapter = new ArrayAdapter<String>(getApplicationContext(),
				                            R.layout.debuger_item_layout,
				                            R.id.debug_item);
		mListView = getListView();
		mListView.setAdapter(mAdapter);
		Log.regOnLogListener(this);
	}
	@Override
	protected void onResume() {
		super.onResume();
		mFilterText.clearFocus();
	}
	@Override
	protected void onDestroy() {
		super.onDestroy();
		Log.unRegOnLogListener(this);
	}
	
	/**
	 * 
	 * @param file
	 * @param external save to external storage(i.e. SDcard) or not.
	 */
	public void saveLog(String file, boolean external) {
		File logFile;
		if (external) {
			if (!android.os.Environment.getExternalStorageState().equals(
					android.os.Environment.MEDIA_MOUNTED)) {
				Toast.makeText(getApplicationContext(), "The SDCard is not ready", Toast.LENGTH_SHORT).show();
				return ;
			}
			File dir = new File(Environment.getExternalStorageDirectory(), LOG_DIR);
			if (!dir.exists()) {
				dir.mkdirs();
			}
			logFile = new File(dir, "log");
		} else {
			logFile = new File(Environment.getDataDirectory(), LOG_DIR);
		}
		
		try {
			logFile.createNewFile();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			Log.e(TAG, "can not create new file: " + logFile.getName());
			e.printStackTrace();
		}
		
		BufferedWriter bw = null;;
		try {
			 bw = new BufferedWriter(new FileWriter(logFile));
		} catch (IOException e) {
			e.printStackTrace();
		} finally {}
	
		int count  = mAdapter.getCount();

		try {
			for (int i = 0 ; i < count ; i++) {
				bw.write(mAdapter.getItem(i));
				bw.newLine();
			}
			bw.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}


	}
	
	private void startLog() {
		mLogging = true;
	}
	private void stopLog() {
		mLogging = false;
	}
	private void update(String log) {
		mAdapter.add(log);
		mAdapter.notifyDataSetChanged();
//		mListView.scrollTo(mListView.getBottom(), mListView.getLeft());
	}
	
	/**
	 * 
	 * @param level Log level
	 * @param reg  the regular express to match.
	 *        if empty (not null) matchs ALL.
	 */
	public void filter() {
		mAdapter.clear();
		for (LogMessage m : mList) {
			doUpdate(m);
		}
	}
	public void doUpdate(LogMessage message) {
		if (mLogging && message.getLevel() <= mLevel && (mReg == "" ? true : message.getLog().indexOf(mReg) != -1)) {
			update(getLogStr(message));
		}
	}
	public void addLog(LogMessage message) {
		mList.add(message);
	}
	public void onLog(int level, String message) {
		// TODO Auto-generated method stub
		LogMessage m = new LogMessage(level, message);
		addLog(m);
		
		doUpdate(m);
	}
	
	/**
	 *  
	 * @param m
	 * @return according the log level, return the Log message.
	 */
	public String getLogStr(LogMessage m) {
		String str = "";
		switch (m.getLevel()) {
		case Log.LEVEL_D:
			if (mLevel >= Log.LEVEL_D) {
				str = D + m.getLog();
			}
			break;
		case Log.LEVEL_E:
			if (mLevel >= Log.LEVEL_E) {
				str = E + m.getLog();
			}
			break;
		case Log.LEVEL_I:
			if (mLevel >= Log.LEVEL_I) {
				str = I + m.getLog();
			}
			break;
		case Log.LEVEL_V:
			if (mLevel >= Log.LEVEL_V) {
				str = V + m.getLog();
			}
			break;
		case Log.LEVEL_W:
			if (mLevel >= Log.LEVEL_W) {
				str = W + m.getLog();
			}
			break;
		default:
			Log.e(TAG, "a invalid log level");
			break;
		}
		
		return str;
	}
	// XXX tst only remvoe this when everything is done.
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		switch (keyCode) {
		case KeyEvent.KEYCODE_D:
			Log.d(TAG, "a tst log form debuger developer " + Math.random());
			break;
		case KeyEvent.KEYCODE_E:
			Log.e(TAG, "a tst log form debuger developer " + Math.random());
			break;
		case KeyEvent.KEYCODE_V:
			Log.v(TAG, "a tst log form debuger developer " + Math.random());
			break;
		case KeyEvent.KEYCODE_W:
			Log.w(TAG, "a tst log form debuger developer " + Math.random());
		case KeyEvent.KEYCODE_I:
			Log.i(TAG, "a tst log form debuger developer " + Math.random());
			break;
//		case KeyEvent.KEYCODE_F:
//			Filter filter = mAdapter.getFilter();
//			String constraint = "Debugerr";
//			// asynchronously filter
//			filter.filter(constraint);  
//			Log.d("Debuger.Filter", "filtered by constraint: " + constraint);
//			break;
		default:
			break;
		}
		return super.onKeyDown(keyCode, event);
	}
	
	private class LogMessage {
		private int mLevel;
		private String mLog;
		
		public LogMessage(int level, String message) {
			mLevel = level;
			mLog = message;
		}

		public int getLevel() {
			return mLevel;
		}

		public String getLog() {
			return mLog;
		}
		
	}
}
